package com.lehecai.ucenter.action.user;

import com.lehecai.core.EnabledStatus;
import com.lehecai.core.YesNoStatus;
import com.lehecai.core.exception.cache.CacheException;
import com.lehecai.core.service.cache.CacheService;
import com.lehecai.ucenter.action.BaseAction;
import com.lehecai.ucenter.constant.AuthenticateStatus;
import com.lehecai.ucenter.constant.FormatType;
import com.lehecai.ucenter.entity.permission.User;
import com.lehecai.ucenter.service.permission.UserService;
import com.lehecai.ucenter.utils.GoogleAuthenticator;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletResponse;


public class OpenAuthenticateAction extends BaseAction {

	private UserService userService;
    private CacheService cacheService;
    private String cacheName;

    private static final String JSON_CODE = "code";
    private static final String JSON_MESSAGE = "message";
    private static final String JSON_DATA = "data";
    private static final String JSON_DATA_USERNAME = "username";
    private static final String JSON_DATA_FORMAT = "format";

	private String username;
	private String password;
	private String format;

	public String handle() {
        HttpServletResponse response = ServletActionContext.getResponse();

        if (StringUtils.isEmpty(format)) {
            format = FormatType.FORMAT_TYPE_RAW.getKey();
        }
        FormatType formatType = FormatType.getByKey(format);

        logger.info("进入验证身份");
		if (StringUtils.isEmpty(username)) {
			logger.error("用户名为空");
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE_USERNAME_NOT_NULL));
			return null;
		}
		if (StringUtils.isEmpty(password) || password.length() != 6) {
			logger.error("密码为空或长度错误");
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE_PASSWORD_NOT_NULL));
			return null;
		}
        logger.info("验证身份通过参数完整性验证，参数包括:username={}, password={}, format={}", new Object[]{username, password, format});


        User user = userService.findByUsername(username);
		if (user == null) {
			logger.error("用户不存在:{}", username);
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE));
            return null;
		}

        if (user.getEnabled().getValue() == EnabledStatus.DISABLED.getValue()) {
            logger.error("用户状态为不可用状态:username={}, enabled={}", new Object[]{username, user.getEnabled().getName()});
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE));
            return null;
        }

        if (user.getOtp().getValue() == YesNoStatus.NO.getValue()) {
            logger.error("用户未开启动态密码验证功能，请联系管理员！username={}", new Object[]{username});
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE));
            return null;
        }

        //验证动态密码

        String cachedOneTimePassword = null;
        try {
            cachedOneTimePassword = cacheService.getObject(String.class, cacheName, password);
        } catch (CacheException e) {
            logger.error("从缓存中读取动态密码出错, key={}", password);
            logger.error(e.getMessage(), e);
        }

        if (!StringUtils.isEmpty(cachedOneTimePassword)) {
            logger.error("动态密码已被使用:username={}, cachedOneTimePassword={}", new Object[]{username, cachedOneTimePassword});
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE_PASSWORD_USED));
            return null;
        }

        long t = System.currentTimeMillis();
        GoogleAuthenticator ga = new GoogleAuthenticator();
        ga.setWindowSize(5);  //should give 5 * 30 seconds of grace...

        long code = 0L;
        try {
            code = Long.parseLong(password);
        } catch (NumberFormatException e) {
            logger.error("动态密码格式不正确，转换成long错误:username={}, password={}", new Object[]{username, password});
            logger.error(e.getMessage(), e);
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE));
            return null;
        }

        boolean r = ga.check_code(user.getSecretKey(), code, t);
        if (!r) {
            logger.error("动态密码不正确:username={}, otp={}", new Object[]{username, password});
            super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_FAILURE));
            return null;
        }

        try {
            cacheService.setObject(cacheName, password, password);
        } catch (CacheException e) {
            logger.error("设置缓存出错, key={}", password);
            logger.error(e.getMessage(), e);
        }

        logger.info("用户身份认证通过！username={}", username);
        super.writeRs(response, this.generateResponseResult(formatType, AuthenticateStatus.AUTHENTICATE_STATUS_SUCCESS));

		logger.info("验证身份结束");
		return null;
	}

    private String generateResponseResult(FormatType formatType, AuthenticateStatus authenticateStatus) {
        String result = null;
        if (formatType.getCode() == FormatType.FORMAT_TYPE_RAW.getCode()) {
            StringBuffer sb = new StringBuffer();
            sb.append(JSON_CODE).append("=").append(authenticateStatus.getCode());
            sb.append("&");
            sb.append(JSON_MESSAGE).append("=").append(authenticateStatus.getMessage());
            if (!StringUtils.isEmpty(username)) {
                sb.append("&");
                sb.append(JSON_DATA).append(".").append(JSON_DATA_USERNAME).append("=").append(username);
            }
            if (!StringUtils.isEmpty(format)) {
                sb.append("&");
                sb.append(JSON_DATA).append(".").append(JSON_DATA_FORMAT).append("=").append(format);
            }
            result = sb.toString();
        } else if (formatType.getCode() == FormatType.FORMAT_TYPE_JSON.getCode()) {
            JSONObject jsonObject = new JSONObject();
            JSONObject jsonDataObject = new JSONObject();

            jsonObject.put(JSON_CODE, authenticateStatus.getCode());
            jsonObject.put(JSON_MESSAGE, authenticateStatus.getMessage());
            jsonDataObject.put(JSON_DATA_USERNAME, username);
            jsonDataObject.put(JSON_DATA_FORMAT, format);
            jsonObject.put(JSON_DATA, jsonDataObject);
            result = jsonObject.toString();
        }
        return result;
    }

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

    public CacheService getCacheService() {
        return cacheService;
    }

    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }

    public String getFormat() {
        return format;
    }

    public void setFormat(String format) {
        this.format = format;
    }
}
